﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;

namespace YArchitech.Plumbing
{
	public class BeamData
	{
		public BeamData(Element e, Transform tf)
		{
			this.Entbaem = e;
			this.tForm = tf;
			Curve curve;
			if (e is Wall)
			{
				curve = ((e as Wall).Location as LocationCurve).Curve;
			}
			else
			{
				curve = ((e as FamilyInstance).Location as LocationCurve).Curve;
			}
			XYZ xyz = curve.GetEndPoint(0);
			XYZ xyz2 = curve.GetEndPoint(1);
			if (tf != null)
			{
				xyz += tf.Origin;
				xyz2 += tf.Origin;
			}
			if (xyz.X > xyz2.X)
			{
				this.SPoint = new XYZ(xyz2.X, xyz2.Y, 0.0);
				this.EPoint = new XYZ(xyz.X, xyz.Y, 0.0);
				return;
			}
			this.SPoint = new XYZ(xyz.X, xyz.Y, 0.0);
			this.EPoint = new XYZ(xyz2.X, xyz2.Y, 0.0);
		}

		public Element Entbaem { get; set; }

		public XYZ SPoint { get; set; }

		public XYZ EPoint { get; set; }

		public bool IsEqual(BeamData src)
		{
			return src.Entbaem == this.Entbaem || ((this.SPoint.DistanceTo(src.SPoint) < this.dDisError && this.EPoint.DistanceTo(src.EPoint) < this.dDisError) || (this.SPoint.DistanceTo(src.EPoint) < this.dDisError && this.EPoint.DistanceTo(src.SPoint) < this.dDisError));
		}

		public bool IsJoin(BeamData src)
		{
			return !this.IsEqual(src) && (this.SPoint.DistanceTo(src.SPoint) < this.dDisError || this.SPoint.DistanceTo(src.EPoint) < this.dDisError || this.EPoint.DistanceTo(src.EPoint) < this.dDisError || this.EPoint.DistanceTo(src.SPoint) < this.dDisError);
		}

		public bool IsJoinByPoint(BeamData src, XYZ p)
		{
			if (this.IsEqual(src))
			{
				return false;
			}
			if (this.SPoint.DistanceTo(p) < this.EPoint.DistanceTo(p))
			{
				if (this.SPoint.DistanceTo(src.SPoint) < this.dDisError || this.SPoint.DistanceTo(src.EPoint) < this.dDisError)
				{
					return true;
				}
			}
			else if (this.EPoint.DistanceTo(src.EPoint) < this.dDisError || this.EPoint.DistanceTo(src.SPoint) < this.dDisError)
			{
				return true;
			}
			return false;
		}

		public XYZ GetTerPoint(BeamDataManage.SearchStep sStep)
		{
			if (this.IsSelfParallel())
			{
				if (sStep == BeamDataManage.SearchStep.Parallel_Front || sStep == BeamDataManage.SearchStep.Vertical_Up)
				{
					if (this.SPoint.X > this.EPoint.X)
					{
						return this.SPoint;
					}
					return this.EPoint;
				}
				else if (sStep == BeamDataManage.SearchStep.Parallel_Back || sStep == BeamDataManage.SearchStep.Vertical_Down)
				{
					if (this.SPoint.X > this.EPoint.X)
					{
						return this.EPoint;
					}
					return this.SPoint;
				}
			}
			else if (this.IsSelfVertical())
			{
				if (sStep == BeamDataManage.SearchStep.Parallel_Back || sStep == BeamDataManage.SearchStep.Vertical_Up)
				{
					if (this.SPoint.Y > this.EPoint.Y)
					{
						return this.SPoint;
					}
					return this.EPoint;
				}
				else if (sStep == BeamDataManage.SearchStep.Vertical_Down || sStep == BeamDataManage.SearchStep.Parallel_Front)
				{
					if (this.SPoint.Y > this.EPoint.Y)
					{
						return this.EPoint;
					}
					return this.SPoint;
				}
			}
			return XYZ.Zero;
		}

		public BeamData GetNextStepBeam(BeamDataManage.SearchStep sStep, List<BeamData> bList)
		{
			if (bList == null || bList.Count <= 0)
			{
				return null;
			}
			List<BeamData> list = (from bb in bList
			where this.IsJoinByPoint(bb, this.GetTerPoint(sStep))
			select bb).ToList<BeamData>();
			List<BeamData> list2 = new List<BeamData>();
			if (this.IsSelfParallel())
			{
				list2 = (from pa in list
				where this.IsParallel(pa) || this.IsVertical(pa)
				select pa).ToList<BeamData>();
			}
			if (list == null || list.Count <= 0)
			{
				return null;
			}
			if (sStep == BeamDataManage.SearchStep.Parallel_Front)
			{
				if (this.IsSelfParallel())
				{
					list2 = (from pa in list
					where this.IsParallel(pa)
					select pa).ToList<BeamData>();
				}
				else if (this.IsSelfVertical())
				{
					list2 = (from pa in list
					where this.IsVertical(pa)
					select pa).ToList<BeamData>();
				}
				using (List<BeamData>.Enumerator enumerator = list2.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						BeamData beamData = enumerator.Current;
						double num = (this.SPoint.X > this.EPoint.X) ? this.SPoint.X : this.EPoint.X;
						if (((beamData.SPoint.X > beamData.EPoint.X) ? beamData.SPoint.X : beamData.EPoint.X) - num > this.dDisError)
						{
							return beamData;
						}
					}
					goto IL_457;
				}
			}
			if (sStep == BeamDataManage.SearchStep.Parallel_Back)
			{
				if (this.IsSelfParallel())
				{
					list2 = (from pa in list
					where this.IsParallel(pa)
					select pa).ToList<BeamData>();
				}
				else if (this.IsSelfVertical())
				{
					list2 = (from pa in list
					where this.IsVertical(pa)
					select pa).ToList<BeamData>();
				}
				using (List<BeamData>.Enumerator enumerator = list2.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						BeamData beamData2 = enumerator.Current;
						double num2 = (this.SPoint.X < this.EPoint.X) ? this.SPoint.X : this.EPoint.X;
						double num3 = (beamData2.SPoint.X < beamData2.EPoint.X) ? beamData2.SPoint.X : beamData2.EPoint.X;
						if (num2 - num3 > this.dDisError)
						{
							return beamData2;
						}
					}
					goto IL_457;
				}
			}
			if (sStep == BeamDataManage.SearchStep.Vertical_Up)
			{
				if (this.IsSelfParallel())
				{
					list2 = (from pa in list
					where this.IsVertical(pa)
					select pa).ToList<BeamData>();
				}
				else if (this.IsSelfVertical())
				{
					list2 = (from pa in list
					where this.IsParallel(pa)
					select pa).ToList<BeamData>();
				}
				using (List<BeamData>.Enumerator enumerator = list2.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						BeamData beamData3 = enumerator.Current;
						double num4 = (this.SPoint.Y > this.EPoint.Y) ? this.SPoint.Y : this.EPoint.Y;
						if (((beamData3.SPoint.Y > beamData3.EPoint.Y) ? beamData3.SPoint.Y : beamData3.EPoint.Y) - num4 > this.dDisError)
						{
							return beamData3;
						}
					}
					goto IL_457;
				}
			}
			if (sStep == BeamDataManage.SearchStep.Vertical_Down)
			{
				if (this.IsSelfParallel())
				{
					list2 = (from pa in list
					where this.IsVertical(pa)
					select pa).ToList<BeamData>();
				}
				else if (this.IsSelfVertical())
				{
					list2 = (from pa in list
					where this.IsParallel(pa)
					select pa).ToList<BeamData>();
				}
				foreach (BeamData beamData4 in list2)
				{
					double num5 = (this.SPoint.Y < this.EPoint.Y) ? this.SPoint.Y : this.EPoint.Y;
					double num6 = (beamData4.SPoint.Y < beamData4.EPoint.Y) ? beamData4.SPoint.Y : beamData4.EPoint.Y;
					if (num5 - num6 > this.dDisError)
					{
						return beamData4;
					}
				}
			}
			IL_457:
			return null;
		}

		public XYZ Direction()
		{
			return (this.SPoint - this.EPoint).Normalize();
		}

		public bool IsParallel(BeamData src)
		{
			double num = src.Direction().AngleTo(this.Direction());
			return Math.Abs(num - 0.0) < this.dAngleError || Math.Abs(num - Math.PI) < this.dAngleError;
		}

		public bool IsSelfParallel()
		{
			double num = XYZ.BasisX.AngleTo(this.Direction());
			return Math.Abs(num - 0.0) < this.dAngleError || Math.Abs(num - Math.PI) < this.dAngleError;
		}

		public bool IsVertical(BeamData src)
		{
			double num = src.Direction().AngleTo(this.Direction());
			return Math.Abs(num - Math.PI*.5) < this.dAngleError || Math.Abs(num - Math.PI - Math.PI*.5) < this.dAngleError;
		}

		public bool IsSelfVertical()
		{
			double num = XYZ.BasisY.AngleTo(this.Direction());
			return Math.Abs(num - 0.0) < this.dAngleError || Math.Abs(num - Math.PI) < this.dAngleError;
		}

		public Transform tForm;

		private double dDisError = 2.5;

		private double dAngleError = 0.001;
	}
}
